package com.way.blockchain.block;

import com.way.blockchain.pow.PowResult;
import com.way.blockchain.pow.ProofOfWork;
import com.way.blockchain.transaction.MerkleTree;
import com.way.blockchain.transaction.Transaction;
import com.way.blockchain.util.ByteUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

/**
 * @author way
 * @create 2023-09-06 9:16
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Block {
    /**
     * 区块hash值
     */
    private String hash;
    /**
     * 前一个区块的hash值
     */
    private String prevBlockHash;
    /**
     * 区块包含的交易
     */
    private List<Transaction> transactions;
    /**
     * 时间戳
     */
    private long timeStamp;
    /**
     * 区块高度
     */
    private long height;
    /**
     * 工作量证明计数器
     */
    private long nonce;

    /**
     * 创建新的区块
     * @param prevBlockHash
     * @param transactions
     * @param height
     * @return
     */
    public static Block newBlock(String prevBlockHash, List<Transaction> transactions, long height) {
        Block block = new Block("", prevBlockHash, transactions, Instant.now().getEpochSecond(), height, 0L);
        ProofOfWork proofOfWork = ProofOfWork.newProofOfWork(block);
        PowResult powResult = proofOfWork.run();
        block.setHash(powResult.getHash());
        block.setNonce(powResult.getNonce());
        return block;
    }


    private static final String ZERO_HASH = Hex.encodeHexString(new byte[32]);

    /**
     * 创建创世区块
     * @return
     */
    public static Block newGenesisBlock(Transaction coinbase) {
        List<Transaction> transactions = new ArrayList<>();
        transactions.add(coinbase);
        return Block.newBlock(ZERO_HASH, transactions,0);
    }

    /**
     * 对区块中的交易信息进行Hash计算
     * @return
     */
    public byte[] hashTransaction() {
        byte[][] txIdArrays = new byte[this.getTransactions().size()][];
        for (int i = 0; i < this.getTransactions().size(); i++) {
            txIdArrays[i] = this.getTransactions().get(i).getData();
        }
        return new MerkleTree(txIdArrays).getRoot().getHash();
    }
}
